package com.zbkj.admin.service;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.zbkj.admin.boot.common.support.IController;
import net.dreamlu.mica.core.result.R;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * 公用函数
 *
 * @param <T>
 */
@SuppressWarnings("all")
public interface BaseService<T> extends IController {


    /**
     * 获取查询表名字
     *
     * @param clazz 手动指定查询表
     * @return 查询类
     */
    default QueryWrapper from(Class<?> clazz) {
        return QueryWrapper.create().from(clazz);
    }

    /**
     * 获取查询表名字
     *
     * @return 查询类
     */
    default QueryWrapper from() {
        return QueryWrapper.create().from(ClassUtil.getTypeArgument(getClass(), 1));
    }

    /**
     * list 数组运算(所有数字类型处理)
     *
     * @param objects              数组数据
     * @param isParallel           是否并行处理
     * @param firstValueExtractor  需计算字段 p -> BigDecimal.valueOf(p.getPrice()),     // 提取价格
     * @param secondValueExtractor 需计算字段 p -> BigDecimal.valueOf(p.getQuantity()),  // 提取数量
     * @param thirdValueExtractor  需计算字段 p -> BigDecimal.valueOf(p.getQuantity()),  // 提取数量
     * @param operator             运算方法  BigDecimal::multiply
     * @param operatorFirst        运算方法  BigDecimal::multiply
     * @param <R>                  数组数据类型
     * @return 计算后的结果
     */
    static <R, I extends Number> Stream<BigDecimal> calculationInt(Stream<R> objects, Boolean isParallel, Function<R, I> firstValueExtractor, Function<R, I> secondValueExtractor,
                                                                   Function<R, I> thirdValueExtractor, BiFunction<BigDecimal, BigDecimal, BigDecimal> operator,
                                                                   BiFunction<BigDecimal, BigDecimal, BigDecimal> operatorFirst) {

        return handlerData(objects, isParallel, firstValueExtractor, secondValueExtractor, null, operator, null);
    }

    /**
     * list 数组运算
     *
     * @param objects              数组数据
     * @param isParallel           是否并行处理
     * @param firstValueExtractor  需计算字段 p -> BigDecimal.valueOf(p.getPrice()),     // 提取价格
     * @param secondValueExtractor 需计算字段 p -> BigDecimal.valueOf(p.getQuantity()),  // 提取数量
     * @param operator             运算方法  BigDecimal::multiply
     * @param <R>                  数组数据类型
     * @return 计算后的结果
     */
    static <R, I extends Number> Stream<BigDecimal> calculationInt(Stream<R> objects, Boolean isParallel, Function<R, I> firstValueExtractor,
                                                                   Function<R, I> secondValueExtractor, BiFunction<BigDecimal, BigDecimal, BigDecimal> operator) {

        return handlerData(objects, isParallel, firstValueExtractor, secondValueExtractor, null, operator, null);
    }

    /**
     * list 数组运算
     *
     * @param objects              数组数据
     * @param isParallel           是否并行处理
     * @param firstValueExtractor  需计算字段 p -> BigDecimal.valueOf(p.getPrice()),     // 提取价格
     * @param secondValueExtractor 需计算字段 p -> BigDecimal.valueOf(p.getQuantity()),  // 提取数量
     * @param operator             运算方法  BigDecimal::multiply
     * @param <R>                  数组数据类型
     * @return 计算后的结果
     */
    static <R> Stream<BigDecimal> calculation(Stream<R> objects, Boolean isParallel, Function<R, BigDecimal> firstValueExtractor,
                                              Function<R, BigDecimal> secondValueExtractor, BiFunction<BigDecimal, BigDecimal, BigDecimal> operator) {
        return handlerData(objects, isParallel, firstValueExtractor, secondValueExtractor, null, operator, null);
    }

    /**
     * list 数组运算(所有数字类型处理)
     *
     * @param objects              数组数据
     * @param isParallel           是否并行处理
     * @param firstValueExtractor  需计算字段 p -> BigDecimal.valueOf(p.getPrice()),     // 提取价格
     * @param secondValueExtractor 需计算字段 p -> BigDecimal.valueOf(p.getQuantity()),  // 提取数量
     * @param thirdValueExtractor  需计算字段 p -> BigDecimal.valueOf(p.getQuantity()),  // 提取数量
     * @param operator             运算方法  BigDecimal::multiply
     * @param operatorFirst        运算方法  BigDecimal::multiply
     * @param <R>                  数组数据类型
     * @return 计算后的结果
     */
    static <R, I extends Number> Stream<BigDecimal> handlerData(Stream<R> objects, Boolean isParallel, Function<R, I> firstValueExtractor,
                                                                Function<R, I> secondValueExtractor, Function<R, I> thirdValueExtractor,
                                                                BiFunction<BigDecimal, BigDecimal, BigDecimal> operator, BiFunction<BigDecimal, BigDecimal, BigDecimal> operatorFirst) {
        return StreamSupport.stream(objects.map(obj -> {
            try {
                BigDecimal first = new BigDecimal(String.valueOf(firstValueExtractor.apply(obj)));
                BigDecimal second = new BigDecimal(String.valueOf(secondValueExtractor.apply(obj)));
                BigDecimal alueExtractor = null;
                if (Objects.nonNull(thirdValueExtractor)) {
                    alueExtractor = new BigDecimal(String.valueOf(thirdValueExtractor.apply(obj)));
                }
                return Objects.nonNull(thirdValueExtractor) ? operatorFirst.apply(operator.apply(first, second), alueExtractor) : operator.apply(first, second);
            } catch (Exception e) {
                return BigDecimal.ZERO;
            }
        }).spliterator(), isParallel);
    }

    /**
     * 数据库商务
     *
     * @param action 事务逻辑
     * @return 是否成功
     */
    default Boolean transaction(TransactionData action) {
        return SpringUtil.getBean(TransactionTemplate.class).execute(a -> {
            try {
                return action.handler();
            } catch (Exception e) {
                a.setRollbackOnly();
                throw new RuntimeException(e);
            }
        });
    }

    /**
     * 事务回调
     */
    @FunctionalInterface
    interface TransactionData {
        boolean handler();
    }

}
